import time
import os

import win32gui
import win32api
import win32con
import win32clipboard
import pyperclip

from worker import worker, dm, lock_wrapper
from exceptions import *

class msyhapp(worker):
    """
    docstring for msyhapp
    """
    def __init__(self, backend:"后台根地址",lock:"锁",config_entity):
        super(msyhapp, self).__init__(backend,lock,config_entity,old_title = "夜神模拟器")
        self.base_picture_path = "msyhapp/image/"
        self.risk = float(config_entity['risk'])

        is_in_desktop = self.findPicture_relative_onlybool("app.bmp")
        is_in_app = self.findPicture_relative_onlybool("zz_index.bmp") or self.findPicture_relative_onlybool("zzhk.bmp")
        is_in_zzhk_inner = self.findPicture_relative_onlybool("zzhk_inner.bmp")
        is_in_login = self.findPicture_relative_onlybool("safe_login.bmp")

        if not (is_in_app or is_in_desktop or is_in_zzhk_inner or is_in_login):
            raise StartBankAppException("开启银行app失败")
        if is_in_desktop:
            self.findPicture_relative_and_click("app.bmp")
            print("开启app")
            time.sleep(20)
        if is_in_zzhk_inner or is_in_login:
            self.back()
            time.sleep(2)
            if is_in_zzhk_inner:
                self.back()

    @lock_wrapper
    def key_login_password(self,password):
        _1 = (85,550)
        _2 = (245,550)
        _3 = (405,550)
        _4 = (85,630)
        _5 = (245,630)
        _6 = (405,630)
        _7 = (85,710)
        _8 = (245,710)
        _9 = (405,710)
        _0 = (245,790)
        _toABC = (85,790)

        _q = (35,550)
        _w = (80,550)
        _e = (125,550)
        _r = (170,550)
        _t = (215,550)
        _y = (250,550)
        _u = (295,550)
        _i = (335,550)
        _o = (380,550)
        _p = (425,550)
        _a = (60,630)
        _s = (105,630)
        _d = (150,630)
        _f = (195,630)
        _g = (240,630)
        _h = (285,630)
        _j = (330,630)
        _k = (375,630)
        _l = (420,630)
        _z = (105,710)
        _x = (150,710)
        _c = (195,710)
        _v = (240,710)
        _b = (285,710)
        _n = (330,710)
        _m = (375,710)

        _shift = (50,710)
        _to123 = (65,790)

        def in_number():
            return self.findPicture_relative_onlybool("login_password_number.bmp")

        def in_alpha():
            return self.findPicture_relative_onlybool("login_password_alpha.bmp")

        def is_lower():
            return self.findPicture_relative_onlybool("login_password_lower.bmp")

        def is_upper():
            return self.findPicture_relative_onlybool("login_password_upper.bmp")

        x1,y1,x2,y2 = win32gui.GetWindowRect(self.hwnd)

        delay = 0.1

        if not in_alpha() and not in_number():
            raise LoginException("安全键盘尚未打开")
        for k in password:
            time.sleep(delay)
            if k.isnumeric():
                if in_number():
                    self.left_click(x1,y1,*(locals().get("_"+k)))
                else:
                    self.left_click(x1,y1,*(locals().get("_to123")))
                    time.sleep(delay)
                    self.left_click(x1,y1,*(locals().get("_"+k)))
            if k.isupper():
                if is_upper():
                    self.left_click(x1,y1,*(locals().get("_"+k)))
                elif is_lower():
                    self.left_click(x1,y1,*(locals().get("_shift")))
                    time.sleep(delay)
                    self.left_click(x1,y1,*(locals().get("_"+k)))
                elif in_number():
                    self.left_click(x1,y1,*(locals().get("_toABC")))
                    time.sleep(delay)
                    if is_lower():
                        self.left_click(x1,y1,*(locals().get("_shift")))
                        time.sleep(delay)
                        self.left_click(x1,y1,*(locals().get("_"+k)))
                    else:
                        self.left_click(x1,y1,*(locals().get("_"+k)))
            if k.islower():
                if is_lower():
                    self.left_click(x1,y1,*(locals().get("_"+k)))
                elif is_upper():
                    self.left_click(x1,y1,*(locals().get("_shift")))
                    time.sleep(delay)
                    self.left_click(x1,y1,*(locals().get("_"+k)))
                elif in_number():
                    self.left_click(x1,y1,*(locals().get("_toABC")))
                    time.sleep(delay)
                    if is_upper():
                        self.left_click(x1,y1,*(locals().get("_shift")))
                        time.sleep(delay)
                        self.left_click(x1,y1,*(locals().get("_"+k)))
                    else:
                        self.left_click(x1,y1,*(locals().get("_"+k)))

    @lock_wrapper
    def key_in_safe_keyboard(self,word):
        _1 = (80,640)
        _2 = (240,640)
        _3 = (400,640)
        _4 = (80,695)
        _5 = (240,695)
        _6 = (400,695)
        _7 = (80,750)
        _8 = (240,750)
        _9 = (400,750)
        _0 = (240,800)
        _point = (80,800)
        _submit = (40,590)
        x1,y1,x2,y2 = win32gui.GetWindowRect(self.hwnd)
        if not self.findPicture_relative_onlybool("submit_in_keyboard2.bmp"):
            raise Exception("安全键盘尚未打开")
        for m in word:
            if m == '.':
                m = 'point'
            self.left_click(x1,y1,*(locals().get("_"+m)))
        else:
            self.left_click(x1,y1,*(locals().get("_submit")))

    @lock_wrapper
    def key_account(self,account):
        _1 = (80,640)
        _2 = (240,640)
        _3 = (400,640)
        _4 = (80,695)
        _5 = (240,695)
        _6 = (400,695)
        _7 = (80,750)
        _8 = (240,750)
        _9 = (400,750)
        _0 = (240,800)
        _point = (80,800)
        _submit = (40,590)
        x1,y1,x2,y2 = win32gui.GetWindowRect(self.hwnd)
        if not self.findPicture_relative_onlybool("in_key_account.bmp"):
            raise BeforePayException("安全键盘尚未打开")
        for m in account:
            if m == '.':
                m = 'point'
            self.left_click(x1,y1,*(locals().get("_"+m)))
        else:
            self.left_click(x1,y1,*(locals().get("_submit")))

    @lock_wrapper
    def key_pay_password(self,password):
        _1 = (80,550)
        _2 = (240,550)
        _3 = (400,550)
        _4 = (80,630)
        _5 = (240,630)
        _6 = (400,630)
        _7 = (80,710)
        _8 = (240,710)
        _9 = (400,710)
        _0 = (240,790)
        _submit = (40,485)
        x1,y1,x2,y2 = win32gui.GetWindowRect(self.hwnd)
        if not self.findPicture_relative_onlybool("in_pay_password.bmp"):
            raise InPayException(self.wid,"付款密码的安全键盘尚未打开")
        for m in password:
            self.left_click(x1,y1,*(locals().get("_"+m)))
        else:
            self.left_click(x1,y1,*(locals().get("_submit")))

    def getHwnd(self):
        self.hwnd = win32gui.FindWindow(None,self.old_title)
        if self.hwnd == 0:
            raise GetMonitorHwndException("模拟器句柄获取失败，请检查模拟器是否打开") 

    def goto_zz(self):
        found,x,y = self.findPicture_relative("zz_index.bmp")
        if not found :
            if self.findPicture_relative_and_click("zzhk.bmp"):
                #relogin,切面
                if self.wait_unit_findpic_or_timeout("zzhk_inner.bmp"):
                    pass#进入了转账内页，完成任务
                elif self.findPicture_relative_onlybool("timeout_relogin.bmp"):
                    self.findPicture_relative_and_click("timeout_relogin.bmp")#自动返回主页，需要重新进入
                    time.sleep(5)
                    return self.goto_zz()
                elif self.findPicture_relative_onlybool("need_to_reload_zz.bmp"):
                    #卡住了，返回前一页
                    print("转账页面卡住了")
                    self.left_click(30,60,3,3)
                    return self.goto_zz()
                else:
                    self.relogin()
            elif self.findPicture_relative_onlybool("zzhk_inner.bmp"):
                pass#已经在转账页面里面
            else:
                raise TryBackToReTryException("没有找到转账入口")
        else:
            self.left_click(x,y)
            time.sleep(2)
            if self.findPicture_relative_and_click("zzhk.bmp"):
                #relogin,切面
                if self.wait_unit_findpic_or_timeout("zzhk_inner.bmp"):
                    pass#进入了转账内页，完成任务
                elif self.findPicture_relative_onlybool("timeout_relogin.bmp"):
                    self.findPicture_relative_and_click("timeout_relogin.bmp")#自动返回主页，需要重新进入
                    time.sleep(5)
                    return self.goto_zz()
                elif self.findPicture_relative_onlybool("need_to_reload_zz.bmp"):
                    #卡住了，返回前一页
                    print("转账页面卡住了")
                    self.left_click(30,60,3,3)
                    return self.goto_zz()
                else:
                    self.relogin()
            elif self.findPicture_relative_onlybool("zzhk_inner.bmp"):
                pass#已经在转账页面里面
            else:
                raise TryBackToReTryException("进入转账/汇款页面失败")
                     

    def fill_bank_info(self,name,account,money):
        if not self.wait_unit_findpic_or_timeout("zzhk_inner.bmp"):
            raise BeforeFillBankInfoErrorException(self.wid,"帐号登录超时或其他异常，暂未处理，请联系开发者进一步确认")
            pass#失败，这里应该对帐号进行解锁
        else:
            print("开始填写转账信息:\n\t户名：{name}\n\t账户:{account}\n\t金额:{money}".format(name=name,account=account,money=money))
            
            self.findPicture_relative_and_click("zzje.bmp")
            time.sleep(0.5)
            try:
                self.key_in_safe_keyboard(str(money))
            except Exception as e:
                raise BankInfoErrorException(self.wid,str(e))
            

            time.sleep(1)

            self.findPicture_relative_and_click("bank_name.bmp")
            # self.copy(account)
            # time.sleep(0.5)
            # self.paste()
            self.c_and_p(name)

            self.findPicture_relative_and_click("bank_account.bmp")
            time.sleep(0.5)
            self.key_account(str(account))
            if self.wait_unit_findpic_or_timeout("bank_account_error.bmp",timeout=4):
                self.back()
                time.sleep(1)
                self.back()
                time.sleep(1)
                self.back()
                raise BankInfoErrorException(self.wid,"银行账号信息异常，请人工确认")
            else:
                return True

        
    def pay(self,retry=False):
        if not self.findPicture_relative_and_click("go_to_pay.bmp") and not retry:
            raise BeforePayException(self.wid,"找不到下一步按键，付款失败")
        if self.wait_unit_findpic_or_timeout("yzm_submit_in_pay.bmp"):
            self.findPicture_relative_and_click("yzm_submit_in_pay.bmp")
            time.sleep(1)
            self.findPicture_relative_and_click("yzm.bmp")
            time.sleep(1)
            if not self.findPicture_relative_onlybool("submit_in_keyboard2.bmp"):
                raise InPayException(self.wid,"输入验证码的安全键盘尚未打开")
            maybe_verify_code = self.get_verify_code()
            if maybe_verify_code is not False:
                self.key_in_safe_keyboard(maybe_verify_code)
            else:
                #重试验证码输入
                self.key_in_safe_keyboard("")
                time.sleep(1)
                self.findPicture_relative_and_click("resend_yzm.bmp")
                self.wait_unit_findpic_or_timeout("yzm_submit_in_pay.bmp")
                self.findPicture_relative_and_click("yzm_submit_in_pay.bmp")
                time.sleep(1)
                self.findPicture_relative_and_click("yzm.bmp")
                time.sleep(1)
                if not self.findPicture_relative_onlybool("submit_in_keyboard2.bmp"):
                    raise InPayException(self.wid,"输入验证码的安全键盘尚未打开")
                maybe_verify_code = self.get_verify_code()
                if maybe_verify_code is not False:
                    self.key_in_safe_keyboard(maybe_verify_code)
                else:
                    #报错，验证码输入失败
                    raise InPayException(self.wid,"输入验证码的安全键盘尚未打开")
            time.sleep(2)
            if self.findPicture_relative_and_click("pay_password.bmp"):
                time.sleep(1)
                self.key_pay_password(self.pay_password)
            else:
                raise InPayException(self.wid,"找不到输入交易密码的窗口")
            time.sleep(2)
            if self.findPicture_relative_and_click("pay.bmp"):
                if self.wait_unit_pic404_or_timeout("waiting_pay.bmp"):
                    if self.wait_unit_findpic_or_timeout("pay_success.bmp"):
                        self.findPicture_relative_and_click("finish_pay_submit.bmp")
                        return self.check_history()
                    elif self.findPicture_relative_onlybool("yzm_falut.bmp"):
                        print("验证码错误")
                        return self.pay(retry=True)
            if self.wait_unit_findpic_or_timeout("pay_success.bmp"):
                self.findPicture_relative_and_click("finish_pay_submit.bmp")
                time.sleep(5)
                return self.check_history()
            raise AfterPayException(self.wid,"未知异常，不能判断是否转账成功")
            
            
    def relogin(self):
        flag,x,y = self.findPicture_relative("login_password.bmp")
        if not flag:
            raise LoginException("不在登陆页面")
        self.left_click(x,y)
        time.sleep(1)
        self.key_login_password(self.login_password)
        time.sleep(1)
        if self.findPicture_relative_and_click("safe_login.bmp"):
            time.sleep(10)
            return True
        else:
            raise LoginException("登陆失败")

    def get_verify_code(self,try_time=10,space=5):
        url = "{backend}/messageService?sender_phone={sender_phone}&IMSI={IMSI}".format(IMSI=self.IMSI,sender_phone="95568",backend=self.backend).replace("+","%2b")
        for i in range(try_time):
            response = self.session.get(url)
            try:
                j = response.json()
                print(j)
                if j.get("err",0) == 0:
                    content = j.get("data",{}).get("content")
                    return content[6:12]
                else:
                    pass
            except Exception as e:
                print(e,response.content)
            time.sleep(space)
        return False

    def back(self):
        x1,y1,x2,y2 = win32gui.GetWindowRect(self.hwnd)
        return self.left_click(x1,y1,35,70)

    def check_history(self):
        time.sleep(2)
        is_in_app = self.findPicture_relative_onlybool("zz_index.bmp") or self.findPicture_relative_onlybool("zzhk.bmp")
        if is_in_app:
            self.goto_zz()
        time.sleep(3)
        is_in_zzhk_inner = self.findPicture_relative_onlybool("zzhk_inner.bmp")
        if is_in_zzhk_inner and self.findPicture_relative_and_click("zz_history.bmp"):
            time.sleep(2)
            if self.findPicture_relative_and_click("check.bmp"):
                time.sleep(5)
                x1,y1,x2,y2 = win32gui.GetWindowRect(self.hwnd)
                self.left_click(x1,y1,200,260)
                time.sleep(1)
                success = self.findPicture_relative_onlybool("success.bmp")
                fail = self.findPicture_relative_onlybool("fail.bmp")
                if success:
                    print("转账成功")
                    self.back()
                    time.sleep(1)
                    self.back()
                    time.sleep(1)
                    self.back()
                    return True
                elif fail:
                    name_error = self.findPicture_relative_onlybool("name_error.bmp")
                    self.back()
                    time.sleep(1)
                    self.back()
                    time.sleep(1)
                    self.back()
                    if name_error:
                        raise BankInfoErrorException(self.wid,"收款人户名不符，需要人工处理确认")
                    else:
                        raise AfterPayException(self.wid,"转账失败")
                else:
                    self.back()
                    time.sleep(1)
                    self.back()
                    time.sleep(1)
                    self.back()
                    raise AfterPayException(self.wid,"未识别到是成功还是失败")
